home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / arcers / tarsrc.zip / TARSRC.TAR / tar-1.11.2 / gnu.c < prev    next >
C/C++ Source or Header  |  1993-11-15  |  15KB  |  691 lines

  1. /* GNU dump extensions to tar.
  2.    Copyright (C) 1988, 1992, 1993 Free Software Foundation
  3.  
  4. This file is part of GNU Tar.
  5.  
  6. GNU Tar is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. GNU Tar is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Tar; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include <stdio.h>
  21. #include <sys/types.h>
  22. #include <ctype.h>
  23. #include <errno.h>
  24. #ifndef STDC_HEADERS
  25. extern int errno;
  26. #endif
  27. #include <time.h>
  28.  
  29. #include "tar.h"
  30. #include "port.h"
  31.  
  32. #ifndef S_ISLNK
  33. #define lstat stat
  34. #endif
  35.  
  36. #ifndef USE_PROTOTYPES
  37. time_t time ();
  38. #endif
  39.  
  40. extern time_t new_time;
  41. extern FILE *msg_file;
  42.  
  43. #ifndef USE_PROTOTYPES
  44. void addname ();
  45. int check_exclude ();
  46. extern PTR ck_malloc ();
  47. extern PTR ck_realloc ();
  48. int confirm ();
  49. extern PTR init_buffer ();
  50. extern char *get_buffer ();
  51. int is_dot_or_dotdot ();
  52. extern void add_buffer ();
  53. extern void flush_buffer ();
  54. void name_gather ();
  55. int recursively_delete ();
  56. void skip_file ();
  57. char *un_quote_string ();
  58.  
  59. extern char *new_name ();
  60.  
  61. static void add_dir_name ();
  62. #else
  63. #include "gnu_p.h"
  64. #include "port_p.h"
  65. #include "tar_p.h"
  66. #include "buffer_p.h"
  67. #include "list_p.h"
  68. #endif
  69.  
  70. struct dirname
  71.   {
  72.     struct dirname *next;
  73.     char *name;
  74.     char *dir_text;
  75.     int dev;
  76.     int ino;
  77.     int allnew;
  78.   };
  79. static struct dirname *dir_list;
  80. static time_t this_time;
  81.  
  82. void
  83. add_dir (name, dev, ino, text)
  84.      char *name;
  85.      char *text;
  86.      dev_t dev;
  87.      ino_t ino;
  88. {
  89.   struct dirname *dp;
  90.  
  91.   dp = (struct dirname *) ck_malloc (sizeof (struct dirname));
  92.   if (!dp)
  93.     abort ();
  94.   dp->next = dir_list;
  95.   dir_list = dp;
  96.   dp->dev = dev;
  97.   dp->ino = ino;
  98.   dp->name = ck_malloc (strlen (name) + 1);
  99.   strcpy (dp->name, name);
  100.   dp->dir_text = text;
  101.   dp->allnew = 0;
  102. }
  103.  
  104. void
  105. read_dir_file ()
  106. {
  107.   int dev;
  108.   int ino;
  109.   char *strp;
  110.   FILE *fp;
  111.   char buf[512];
  112.   static char *path = 0;
  113.  
  114.   if (path == 0)
  115.     path = ck_malloc (PATH_MAX);
  116.   time (&this_time);
  117.   if (gnu_dumpfile[0] != '/')
  118.     {
  119. #if defined(__MSDOS__) || defined(HAVE_GETCWD) || defined(_POSIX_VERSION)
  120.       if (!getcwd (path, PATH_MAX))
  121.     {
  122.       msg ("Couldn't get current directory.");
  123.       exit (EX_SYSTEM);
  124.     }
  125. #else
  126.       char *getwd ();
  127.  
  128.       if (!getwd (path))
  129.     {
  130.       msg ("Couldn't get current directory: %s", path);
  131.       exit (EX_SYSTEM);
  132.     }
  133. #endif
  134.       /* If this doesn't fit, we're in serious trouble */
  135.       strcat (path, "/");
  136.       strcat (path, gnu_dumpfile);
  137.       gnu_dumpfile = path;
  138.     }
  139.   fp = fopen (gnu_dumpfile, "r");
  140.   if (fp == 0 && errno != ENOENT)
  141.     {
  142.       msg_perror ("Can't open %s", gnu_dumpfile);
  143.       return;
  144.     }
  145.   if (!fp)
  146.     return;
  147.   fgets (buf, sizeof (buf), fp);
  148.   if (!f_new_files)
  149.     {
  150.       f_new_files++;
  151.       new_time = atol (buf);
  152.     }
  153.   while (fgets (buf, sizeof (buf), fp))
  154.     {
  155.       strp = &buf[strlen (buf)];
  156.       if (strp[-1] == '\n')
  157.     strp[-1] = '\0';
  158.       strp = buf;
  159.       dev = atol (strp);
  160.       while (isdigit (*strp))
  161.     strp++;
  162.       ino = atol (strp);
  163.       while (isspace (*strp))
  164.     strp++;
  165.       while (isdigit (*strp))
  166.     strp++;
  167.       strp++;
  168.       add_dir (un_quote_string (strp), (dev_t)dev, (ino_t)ino, (char *) 0);
  169.     }
  170.   fclose (fp);
  171. }
  172.  
  173. void
  174. write_dir_file ()
  175. {
  176.   FILE *fp;
  177.   struct dirname *dp;
  178.   char *str;
  179.   extern char *quote_copy_string ();
  180.  
  181.   fp = fopen (gnu_dumpfile, "w");
  182.   if (fp == 0)
  183.     {
  184.       msg_perror ("Can't write to %s", gnu_dumpfile);
  185.       return;
  186.     }
  187.   fprintf (fp, "%lu\n", this_time);
  188.   for (dp = dir_list; dp; dp = dp->next)
  189.     {
  190.       if (!dp->dir_text)
  191.     continue;
  192.       str = quote_copy_string (dp->name);
  193.       if (str)
  194.     {
  195.       fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, str);
  196.       free (str);
  197.     }
  198.       else
  199.     fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, dp->name);
  200.     }
  201.   fclose (fp);
  202. }
  203.  
  204. struct dirname *
  205. get_dir (name)
  206.      char *name;
  207. {
  208.   struct dirname *dp;
  209.  
  210.   for (dp = dir_list; dp; dp = dp->next)
  211.     {
  212.       if (!strcmp (dp->name, name))
  213.     return dp;
  214.     }
  215.   return 0;
  216. }
  217.  
  218.  
  219. /* Collect all the names from argv[] (or whatever), then expand them into
  220.    a directory tree, and put all the directories at the beginning. */
  221. void
  222. collect_and_sort_names ()
  223. {
  224.   struct name *n, *n_next;
  225.   int num_names;
  226.   struct stat statbuf;
  227. #ifndef USE_PROTOTYPES
  228.   int name_cmp ();
  229.   char *merge_sort ();
  230. #endif
  231.  
  232.   name_gather ();
  233.  
  234.   if (gnu_dumpfile)
  235.     read_dir_file ();
  236.   if (!namelist)
  237.     addname (".");
  238.   for (n = namelist; n; n = n_next)
  239.     {
  240.       n_next = n->next;
  241.       if (n->found || n->dir_contents)
  242.     continue;
  243.       if (n->regexp)        /* FIXME just skip regexps for now */
  244.     continue;
  245.       if (n->change_dir)
  246.     if (chdir (n->change_dir) < 0)
  247.       {
  248.         msg_perror ("can't chdir to %s", n->change_dir);
  249.         continue;
  250.       }
  251.  
  252. #ifdef AIX
  253.       if (statx (n->name, &statbuf, STATSIZE, STX_HIDDEN | STX_LINK))
  254. #else
  255.       if (lstat (n->name, &statbuf) < 0)
  256. #endif /* AIX */
  257.     {
  258.       msg_perror ("can't stat %s", n->name);
  259.       continue;
  260.     }
  261.       if (S_ISDIR (statbuf.st_mode))
  262.     {
  263.       n->found++;
  264.       add_dir_name (n->name, statbuf.st_dev);
  265.     }
  266.     }
  267.  
  268.   num_names = 0;
  269.   for (n = namelist; n; n = n->next)
  270.     num_names++;
  271.   namelist = (struct name *) merge_sort ((PTR) namelist, num_names, (char *) (&(namelist->next)) - (char *) namelist, name_cmp);
  272.  
  273.   for (n = namelist; n; n = n->next)
  274.     {
  275.       n->found = 0;
  276.     }
  277.   if (gnu_dumpfile)
  278.     write_dir_file ();
  279. }
  280.  
  281. int
  282. name_cmp (n1, n2)
  283.      struct name *n1, *n2;
  284. {
  285.   if (n1->found)
  286.     {
  287.       if (n2->found)
  288.     return strcmp (n1->name, n2->name);
  289.       else
  290.     return -1;
  291.     }
  292.   else if (n2->found)
  293.     return 1;
  294.   else
  295.     return strcmp (n1->name, n2->name);
  296. }
  297.  
  298. int
  299. dirent_cmp (p1, p2)
  300.      const PTR p1;
  301.      const PTR p2;
  302. {
  303.   char *frst, *scnd;
  304.  
  305.   frst = (*(char **) p1) + 1;
  306.   scnd = (*(char **) p2) + 1;
  307.  
  308.   return strcmp (frst, scnd);
  309. }
  310.  
  311. char *
  312. get_dir_contents (p, device)
  313.      char *p;
  314.      int device;
  315. {
  316.   DIR *dirp;
  317.   register struct dirent *d;
  318.   char *new_buf;
  319.   char *namebuf;
  320.   int bufsiz;
  321.   int len;
  322.   PTR the_buffer;
  323.   char *buf;
  324.   size_t n_strs;
  325.   /*    int n_size;*/
  326.   char *p_buf;
  327.   char **vec, **p_vec;
  328.  
  329.   extern int errno;
  330.  
  331.   errno = 0;
  332.   dirp = opendir (p);
  333.   bufsiz = strlen (p) + NAMSIZ;
  334.   namebuf = ck_malloc (bufsiz + 2);
  335.   if (!dirp)
  336.     {
  337.       if (errno)
  338.     msg_perror ("can't open directory %s", p);
  339.       else
  340.     msg ("error opening directory %s", p);
  341.       new_buf = NULL;
  342.     }
  343.   else
  344.     {
  345.       struct dirname *dp;
  346.       int all_children;
  347.  
  348.       dp = get_dir (p);
  349.       all_children = dp ? dp->allnew : 0;
  350.       (void) strcpy (namebuf, p);
  351.       if (p[strlen (p) - 1] != '/')
  352.     (void) strcat (namebuf, "/");
  353.       len = strlen (namebuf);
  354.  
  355.       the_buffer = init_buffer ();
  356.       while (d = readdir (dirp))
  357.     {
  358.       struct stat hs;
  359.  
  360.       /* Skip . and .. */
  361.       if (is_dot_or_dotdot (d->d_name))
  362.         continue;
  363.       if (NLENGTH (d) + len >= bufsiz)
  364.         {
  365.           bufsiz += NAMSIZ;
  366.           namebuf = ck_realloc (namebuf, bufsiz + 2);
  367.         }
  368.       (void) strcpy (namebuf + len, d->d_name);
  369. #ifdef AIX
  370.       if (0 != f_follow_links ?
  371.           statx (namebuf, &hs, STATSIZE, STX_HIDDEN) :
  372.           statx (namebuf, &hs, STATSIZE, STX_HIDDEN | STX_LINK))
  373. #else
  374.       if (0 != f_follow_links ? stat (namebuf, &hs) : lstat (namebuf, &hs))
  375. #endif
  376.         {
  377.           msg_perror ("can't stat %s", namebuf);
  378.           continue;
  379.         }
  380.       if ((f_local_filesys && device != hs.st_dev)
  381.           || (f_exclude && check_exclude (namebuf)))
  382.         add_buffer (the_buffer, "N", 1);
  383. #ifdef AIX
  384.       else if (S_ISHIDDEN (hs.st_mode))
  385.         {
  386.           add_buffer (the_buffer, "D", 1);
  387.           strcat (d->d_name, "A");
  388.           d->d_namlen++;
  389.         }
  390. #endif /* AIX */
  391.       else if (S_ISDIR (hs.st_mode))
  392.         {
  393.           if (dp = get_dir (namebuf))
  394.         {
  395.           if (dp->dev != hs.st_dev
  396.               || dp->ino != hs.st_ino)
  397.             {
  398.               if (f_verbose)
  399.             msg ("directory %s has been renamed.", namebuf);
  400.               dp->allnew = 1;
  401.               dp->dev = hs.st_dev;
  402.               dp->ino = hs.st_ino;
  403.             }
  404.           dp->dir_text = "";
  405.         }
  406.           else
  407.         {
  408.           if (f_verbose)
  409.             msg ("Directory %s is new", namebuf);
  410.           add_dir (namebuf, hs.st_dev, hs.st_ino, "");
  411.           dp = get_dir (namebuf);
  412.           dp->allnew = 1;
  413.         }
  414.           if (all_children)
  415.         dp->allnew = 1;
  416.  
  417.           add_buffer (the_buffer, "D", 1);
  418.         }
  419.       else if (!all_children
  420.            && f_new_files
  421.            && new_time > hs.st_mtime
  422.            && (f_new_files > 1
  423.                || new_time > hs.st_ctime))
  424.         add_buffer (the_buffer, "N", 1);
  425.       else
  426.         add_buffer (the_buffer, "Y", 1);
  427.       add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1));
  428.     }
  429.       add_buffer (the_buffer, "\000\000", 2);
  430.       closedir (dirp);
  431.  
  432.       /* Well, we've read in the contents of the dir, now sort them */
  433.       buf = get_buffer (the_buffer);
  434.       if (buf[0] == '\0')
  435.     {
  436.       flush_buffer (the_buffer);
  437.       new_buf = NULL;
  438.     }
  439.       else
  440.     {
  441.       n_strs = 0;
  442.       for (p_buf = buf; *p_buf;)
  443.         {
  444.           int tmp;
  445.  
  446.           tmp = strlen (p_buf) + 1;
  447.           n_strs++;
  448.           p_buf += tmp;
  449.         }
  450.       vec = (char **) ck_malloc (sizeof (char *) * (n_strs + 1));
  451.       for (p_vec = vec, p_buf = buf; *p_buf; p_buf += strlen (p_buf) + 1)
  452.         *p_vec++ = p_buf;
  453.       *p_vec = 0;
  454.       qsort ((PTR) vec, n_strs, sizeof (char *), dirent_cmp);
  455.       new_buf = (char *) ck_malloc (p_buf - buf + 2);
  456.       for (p_vec = vec, p_buf = new_buf; *p_vec; p_vec++)
  457.         {
  458.           char *p_tmp;
  459.  
  460.           for (p_tmp = *p_vec; *p_buf++ = *p_tmp++;)
  461.         ;
  462.         }
  463.       *p_buf++ = '\0';
  464.       free (vec);
  465.       flush_buffer (the_buffer);
  466.     }
  467.     }
  468.   free (namebuf);
  469.   return new_buf;
  470. }
  471.  
  472. /* p is a directory.  Add all the files in P to the namelist.  If any of the
  473.    files is a directory, recurse on the subdirectory. . . */
  474. static void
  475. add_dir_name (p, device)
  476.      char *p;
  477.      int device;
  478. {
  479.   char *new_buf;
  480.   char *p_buf;
  481.  
  482.   char *namebuf;
  483.   int buflen;
  484.   register int len;
  485.   int sublen;
  486.  
  487.   /*    PTR the_buffer;*/
  488.  
  489.   /*    char *buf;*/
  490.   /*    char **vec,**p_vec;*/
  491.   /*    int n_strs,n_size;*/
  492.  
  493.   struct name *n;
  494.  
  495.   int dirent_cmp ();
  496.  
  497.   new_buf = get_dir_contents (p, device);
  498.  
  499.   for (n = namelist; n; n = n->next)
  500.     {
  501.       if (!strcmp (n->name, p))
  502.     {
  503.       n->dir_contents = new_buf ? new_buf : "\0\0\0\0";
  504.       break;
  505.     }
  506.     }
  507.  
  508.   if (new_buf)
  509.     {
  510.       len = strlen (p);
  511.       buflen = NAMSIZ <= len ? len + NAMSIZ : NAMSIZ;
  512.       namebuf = ck_malloc (buflen + 1);
  513.  
  514.       (void) strcpy (namebuf, p);
  515.       if (namebuf[len - 1] != '/')
  516.     {
  517.       namebuf[len++] = '/';
  518.       namebuf[len] = '\0';
  519.     }
  520.       for (p_buf = new_buf; *p_buf; p_buf += sublen + 1)
  521.     {
  522.       sublen = strlen (p_buf);
  523.       if (*p_buf == 'D')
  524.         {
  525.           if (len + sublen >= buflen)
  526.         {
  527.           buflen += NAMSIZ;
  528.           namebuf = ck_realloc (namebuf, buflen + 1);
  529.         }
  530.           (void) strcpy (namebuf + len, p_buf + 1);
  531.           addname (namebuf);
  532.           add_dir_name (namebuf, device);
  533.         }
  534.     }
  535.       free (namebuf);
  536.     }
  537. }
  538.  
  539. /* Returns non-zero if p is . or ..   This could be a macro for speed. */
  540. int
  541. is_dot_or_dotdot (p)
  542.      char *p;
  543. {
  544.   return (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')));
  545. }
  546.  
  547.  
  548.  
  549.  
  550.  
  551.  
  552. void
  553. gnu_restore (skipcrud)
  554.      int skipcrud;
  555. {
  556.   char *current_dir;
  557.   /*    int current_dir_length; */
  558.  
  559.   char *archive_dir;
  560.   /*    int archive_dir_length; */
  561.   PTR the_buffer;
  562.   char *p;
  563.   DIR *dirp;
  564.   struct dirent *d;
  565.   char *cur, *arc;
  566.   extern struct stat hstat;    /* Stat struct corresponding */
  567.   long size, copied;
  568.   char *from, *to;
  569.   extern union record *head;
  570.  
  571.   dirp = opendir (skipcrud + current_file_name);
  572.  
  573.   if (!dirp)
  574.     {
  575.       /* The directory doesn't exist now.  It'll be created.
  576.                In any case, we don't have to delete any files out
  577.                of it */
  578.       skip_file ((long) hstat.st_size);
  579.       return;
  580.     }
  581.  
  582.   the_buffer = init_buffer ();
  583.   while (d = readdir (dirp))
  584.     {
  585.       if (is_dot_or_dotdot (d->d_name))
  586.     continue;
  587.  
  588.       add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1));
  589.     }
  590.   closedir (dirp);
  591.   add_buffer (the_buffer, "", 1);
  592.  
  593.   current_dir = get_buffer (the_buffer);
  594.   archive_dir = (char *) ck_malloc (hstat.st_size);
  595.   if (archive_dir == 0)
  596.     {
  597.       msg ("Can't allocate %d bytes for restore", hstat.st_size);
  598.       skip_file ((long) hstat.st_size);
  599.       return;
  600.     }
  601.   to = archive_dir;
  602.   for (size = hstat.st_size; size > 0; size -= copied)
  603.     {
  604.       from = findrec ()->charptr;
  605.       if (!from)
  606.     {
  607.       msg ("Unexpected EOF in archive\n");
  608.       break;
  609.     }
  610.       copied = endofrecs ()->charptr - from;
  611.       if (copied > size)
  612.     copied = size;
  613.       bcopy ((PTR) from, (PTR) to, (int) copied);
  614.       to += copied;
  615.       userec ((union record *) (from + copied - 1));
  616.     }
  617.  
  618.   for (cur = current_dir; *cur; cur += strlen (cur) + 1)
  619.     {
  620.       for (arc = archive_dir; *arc; arc += strlen (arc) + 1)
  621.     {
  622.       arc++;
  623.       if (!strcmp (arc, cur))
  624.         break;
  625.     }
  626.       if (*arc == '\0')
  627.     {
  628.       p = new_name (skipcrud + current_file_name, cur);
  629.       if (f_confirm && !confirm ("delete", p))
  630.         {
  631.           free (p);
  632.           continue;
  633.         }
  634.       if (f_verbose)
  635.         fprintf (msg_file, "%s: deleting %s\n", tar, p);
  636.       if (recursively_delete (p))
  637.         {
  638.           msg ("%s: Error while deleting %s\n", tar, p);
  639.         }
  640.       free (p);
  641.     }
  642.  
  643.     }
  644.   flush_buffer (the_buffer);
  645.   free (archive_dir);
  646. }
  647.  
  648. int
  649. recursively_delete (path)
  650.      char *path;
  651. {
  652.   struct stat sbuf;
  653.   DIR *dirp;
  654.   struct dirent *dp;
  655.   char *path_buf;
  656.   /* int path_len; */
  657.  
  658.  
  659.   if (lstat (path, &sbuf) < 0)
  660.     return 1;
  661.   if (S_ISDIR (sbuf.st_mode))
  662.     {
  663.  
  664.       /* path_len=strlen(path); */
  665.       dirp = opendir (path);
  666.       if (dirp == 0)
  667.     return 1;
  668.       while (dp = readdir (dirp))
  669.     {
  670.       if (is_dot_or_dotdot (dp->d_name))
  671.         continue;
  672.       path_buf = new_name (path, dp->d_name);
  673.       if (recursively_delete (path_buf))
  674.         {
  675.           free (path_buf);
  676.           closedir (dirp);
  677.           return 1;
  678.         }
  679.       free (path_buf);
  680.     }
  681.       closedir (dirp);
  682.  
  683.       if (rmdir (path) < 0)
  684.     return 1;
  685.       return 0;
  686.     }
  687.   if (unlink (path) < 0)
  688.     return 1;
  689.   return 0;
  690. }
  691.